#include "app_message.h"
#include "log/log.h"
#include <stdlib.h>
#include <string.h>
#include "json/cJSON.h"
#include <stdio.h>
#include <ctype.h>

/*
得到一个十六进制字符对应的十进制数
'0'-'9' => 0-9
‘A'-'F' => 10-15
‘a'-'f' => 10-15
 */
int hex_to_int(char hex)
{
    if (hex >= '0' && hex <= '9')
    {
        return hex - '0';
    }
    else if (hex >= 'A' && hex <= 'F')
    {
        return hex - 'A' + 10;
    }
    else if (hex >= 'a' && hex <= 'f')
    {
        return hex - 'a' + 10;
    }
}

/**
 * 十六进制字符串转换为对应的字符串
 */
static char *hex_to_chars(char *hex_str, int *chars_len)
{
    // 得到十六进制字符串的长度
    int hex_len = strlen(hex_str);
    // 得到对应字符串的长度，并保存到chars_len
    *chars_len = hex_len / 2;
    // 申请对应字符串的内存空间
    char *chars_str = (char *)malloc(*chars_len + 1);
    
    for (int i = 0; i < hex_len-1; i += 2)
    {
        // 得到高位十六进制字符对应的十进制数
        int high_val = hex_to_int(hex_str[i]);
        // 得到低位十六进制字符对应的十进制数
        int low_val = hex_to_int(hex_str[i + 1]);
        // 将高位和低位组合成一个字节的字符
        chars_str[i / 2] = (high_val << 4) | low_val;
    }
    // 添加字符串结束符
chars_str[hex_len / 2] = '\0';

    return chars_str;
}

/**
 * 字符串转换为十六进制字符串
 */
static char *chars_to_hex(char *chars, int chars_len)
{
    // 动态分配十六进制字符串的内存空间
    char *hex_str = (char *)malloc(chars_len * 2 + 1);
    // 遍历字符串中的每个字符
    for (int i = 0; i < chars_len; i++)
    {
        // 将1个字符对应的2位的十六进制字符保存到hex_str中
        sprintf(&hex_str[i*2], "%02X", chars[i]);
    }
    // 添加十六进制字符串的结束符
hex_str[chars_len * 2] = '\0';

    return hex_str;
}

/**
 * @brief 根据消息二进制数据初始化创建消息结构体
 */
Message *app_message_initByBinary(char *binary, int len)
{
    // 初始Message结构体：动态分配内存
    Message *message = (Message *)malloc(sizeof(Message));
    if (message == NULL)
    {
        log_error("malloc message failed");
        return NULL;
    }
    // 将message的内存所有位置置为0
memset(message, 0, sizeof(Message));   

    // 初始化conn_type属性
    memcpy(&message->conn_type, binary, 1); // 要求前面部分的位必须是0
    // 初始化id_len
    memcpy(&message->id_len, binary+1, 1);
    // 初始化msg_len
    memcpy(&message->msg_len, binary+2, 1);
    // 检查len的合法性
    if (len != 3 + message->id_len + message->msg_len)
    {
        log_error("binary length is not correct");
        // 释放message
        free(message);
        return NULL;
}

    // 初始化payload
    message->payload = malloc(message->id_len + message->msg_len);
memcpy(message->payload, binary+3, message->id_len + message->msg_len);

    log_debug("initByBinary succes, conn_type: %d, id_len: %d, msg_len: %d, payload=%s", 
        message->conn_type, message->id_len, message->msg_len, message->payload);

    // 返回message
    return message;
}

/**
 * @brief 根据消息json数据初始化创建消息结构体
 */
Message *app_message_initByJson(char *json)
{
    // 解析json数据， 得到conn_type, id, msg
    cJSON *root = cJSON_Parse(json);
    if (root == NULL)
    {
        log_error("json parse failed");
        return NULL;
    }
    int conn_type = cJSON_GetObjectItem(root, "conn_type")->valueint;
    char *id_hex = cJSON_GetObjectItem(root, "id")->valuestring;
char *msg_hex = cJSON_GetObjectItem(root, "msg")->valuestring;

    // 初始化Messsage结构体：动态分配内存
    Message *message = (Message *)malloc(sizeof(Message));
    if (message == NULL)
    {
        log_error("malloc message failed");
        cJSON_Delete(root); // 释放cJSON
        return NULL;
    }
    // 初始化内部属性
    message->conn_type = conn_type;
    
    // 得到二进制id, 同时指定message中的id_len
    char *id = hex_to_chars(id_hex, &message->id_len);
    char *msg = hex_to_chars(msg_hex, &message->msg_len);
    log_debug("id_hex=%s, id=%s, id_len=%d", id_hex,id, message->id_len);
    // 将id和msg合并到message的payload中
    message->payload = malloc(message->id_len + message->msg_len);
    memcpy(message->payload, id, message->id_len);
memcpy(message->payload+message->id_len, msg, message->msg_len);

    // 释放cJSON
    cJSON_Delete(root);
    // free(id_hex);  // 不需要我们释放
    // free(msg_hex);
    free(id);
free(msg);

    log_debug("initByJson succes, conn_type: %d, id_len: %d, msg_len: %d, payload=%s", 
        message->conn_type, message->id_len, message->msg_len, message->payload);

    // 返回message
    return message;
}

/**
 * @brief 将消息结构体转换为json数据
 */
int app_message_toJson(Message *message, char *json, int len)
{
    // 创建一个空的cJSON对象来存储conn_type, id, msg
cJSON *root = cJSON_CreateObject();

    // 将message中的conn_type添加到root中
    cJSON_AddNumberToObject(root, "conn_type", message->conn_type);
    // 得到二进制id和msg
    char id[message->id_len];
    char msg[message->msg_len];
    memcpy(id, message->payload, message->id_len);
    memcpy(msg, message->payload+message->id_len, message->msg_len);
    // 得到十六进制id和msg
    char *id_hex = chars_to_hex(id, message->id_len);
char *msg_hex = chars_to_hex(msg, message->msg_len);

    // 将id和msg添加到root中
    cJSON_AddStringToObject(root, "id", id_hex);
cJSON_AddStringToObject(root, "msg", msg_hex);

    // 将root转换为json字符串, 并拷贝到json中
    char *json_str = cJSON_PrintUnformatted(root);
    // 判断json空间是否足够
    if (len < strlen(json_str) +1)
    {
        log_error("json length is not enough");
        cJSON_Delete(root);
        free(json_str);
        free(id_hex);
        free(msg_hex);

        return -1;
    }
    strcpy(json, json_str);

    // 释放资源
    free(id_hex);
    free(msg_hex);
    free(json_str);
cJSON_Delete(root);

    return strlen(json);
}

/**
 * @brief 将消息结构体转换为二进制数据
 * @param binary 二进制数据容器
 * @param len binary的长度
 * @return 实际写入的二进制数据长度
 */
int app_message_toBinary(Message *message, char *binary, int len)
{
    // 检查binary的长度是否足够
    if (len < 3 + message->id_len + message->msg_len)
    {
        log_error("binary length is not enough");
        return -1;
    }

    // 将message中的各个属性数据拷贝到binary对应的位置
    memcpy(binary, &message->conn_type, 1);
    memcpy(binary+1, &message->id_len, 1);
    memcpy(binary+2, &message->msg_len, 1);
memcpy(binary+3, message->payload, message->id_len + message->msg_len);

    return 3 + message->id_len + message->msg_len;
}

/**
 * @brief 释放消息
 */
void app_message_free(Message *message)
{
    if (message->payload)
    {
        free(message->payload);
    }
    free(message);
}
